home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / REVERSEM.ZIP / REVERSEM.CPP < prev    next >
C/C++ Source or Header  |  1994-10-11  |  22KB  |  864 lines

  1. /*--------------------------------------------------------------------------
  2.  
  3.   REVERSEM :
  4.  
  5.   UNIT     : Main unit
  6.  
  7.   This game was developed as my final project in my AI class.  While it is
  8.   still a bit stupid, it should improve drastically in its next release.
  9.  
  10.   COPYRIGHT (C) 1994 Erich P. Gatejen  ALL RIGHTS RESERVED
  11.   This is Freeware.  You may distribute it as you wish.  However, you may not
  12.   distribute a modified version without my consent.
  13.  
  14.   Feel free to cut and paste any algorthm.
  15.  
  16.   NOTE: XTILE is (C) 1992, 1994 by myself.  It is NOT freeware.  You may use
  17.     it for personal projects, but otherwise, it is not to be distributed
  18.     outside this REVERSEM package.  (Contact me if you wish to do
  19.     otherwise)
  20.  
  21. ---------------------------------------------------------------------------*/
  22.  
  23. // ------------------------------------------------------------------------
  24. // --- INCLUDES
  25. // ------------------------------------------------------------------------
  26. #include<stdlib.h>
  27. #include<stdio.h>
  28. extern "C" {
  29.    #include "xtile21!.h"
  30. };
  31. #include<conio.h>
  32. #include<dos.h>
  33. #include<alloc.h>
  34. #include"heap.hpp"
  35. #include"reversem.hpp"
  36. #include"eval.hpp"
  37. #include"spots.hpp"
  38. #include"board.hpp"
  39. #include"graphics.hpp"
  40.  
  41. // ------------------------------------------------------------------------
  42. // --- DEFINITIONS
  43. // ------------------------------------------------------------------------
  44.  
  45. // --- In game status
  46. enum  STATUS { STATUS_CONT = 0, STATUS_END, STATUS_DONE, STATUS_NEW };
  47.  
  48. // --- Timing definitions  (all in miliseconds)
  49. #define  BUTTON_TIME    500
  50.  
  51.  
  52. // ------------------------------------------------------------------------
  53. // --- CLASSES
  54. // ------------------------------------------------------------------------
  55.  
  56. // --- This prototype is need here!
  57. void *getnew( void );
  58.  
  59. // --- MMNode.  A minimax node --------------------------------------------
  60. class  MMNode: public Board {
  61.  
  62.    MMNode    *Children[MAX_CHILDREN];
  63.  
  64.    int        NumberChildren;
  65.  
  66.    SpotStates   Owner;
  67.  
  68.    static       unsigned int    CurrentPly;
  69.    static    Go        AGoTo;
  70.  
  71.  public:
  72.  
  73.    // Constructors
  74.    MMNode( Board  *OldBoard, SpotStates  Who            ) : Board( OldBoard ) {
  75.       Owner = Who;
  76.    };
  77.  
  78.    MMNode( Spot   TheSpots[BOARDXSIZE][BOARDYSIZE],
  79.        SpotStates Who                     ) : Board( TheSpots ) {
  80.       Owner = Who;
  81.    };
  82.  
  83.    MMNode( Spot   TheSpots[BOARDXSIZE][BOARDYSIZE],
  84.        Go     GoTo,     SpotStates Who         ) : Board( TheSpots ) {
  85.       // This will make the move that creates this board
  86.       Owner = Who;
  87.       DoGo( GoTo, Owner );
  88.    };
  89.    ~MMNode( void ) {};
  90.  
  91.    void  SetPly( unsigned int Ply ) { CurrentPly = Ply; };
  92.  
  93.    // Enter the tree,  call for root only
  94.    heuristic  TREE( SpotStates    ThePlayer,
  95.             Go             &TheMove    );
  96.  
  97.    // Enter the tree,  call all non-root nodes
  98.    heuristic  TREE( heuristic     UseThresh,  // For A/B pruning
  99.             heuristic     PassThresh,
  100.             BOOLEAN      Pass  = FALSE  // So we can tell an end move
  101.           );
  102.  
  103.    // DAMN THING IS DRIVING ME NUTS!!!  Overload new.
  104.    void * operator new( size_t size ) { return( getnew() ); };
  105.    void operator delete( void *p  ) {};  // Don't delete anything.
  106.                      // The heap will handle it
  107.    // OK, lesson learned.  DO NOT recursively delete!!!
  108.    // and don't use Borlands heap.  It blows up EVERY time!!!
  109. };
  110.  
  111.  
  112.  
  113. // ------------------------------------------------------------------------
  114. // --- DATA DECLARATIONS
  115. // ------------------------------------------------------------------------
  116.  
  117. // --- Static members of MMNode
  118.    unsigned int    MMNode::CurrentPly;
  119.    Go        MMNode::AGoTo;
  120.  
  121. // --- Global variables
  122.  
  123.    // Plys for each Brain levels
  124.    unsigned int  MaxPlys4Level[EXPERIMENTAL+1] = {
  125.  
  126.       2, // Simpleton
  127.       3, // Dullard
  128.       3, // Average
  129.       4, // Swift
  130.       5, // Genius           // <- 5 may be too high, I'm not sure.
  131.       6, // Experimental
  132.  
  133.       // NOTE: With the heap limit set the way it is, any plys over
  134.       // 5 may cause it to actually get stupider <sic>.
  135.  
  136.    };
  137.  
  138.    // Boards
  139.    Board    MasterBoard;
  140.  
  141.    // Default the brain setting at the lowest level.
  142.    BRAIN    BrainSetting = SIMPLETON;
  143.  
  144. // --- Define the graphics control item
  145.    GraphicsControl        GCI;
  146.  
  147. // --- Give use a bigger stack!!!
  148.    extern unsigned _stklen = ( 16 * 1024 );
  149.  
  150. // --- Define the heap for the minimax tree.
  151.    Heap   MMHeap( sizeof( class MMNode ) );
  152.  
  153. // --- Running score
  154.    int      RunningScore = 0;
  155.  
  156. // --- Flag show heuristic
  157.    BOOLEAN  ShowH = FALSE;
  158.  
  159.  
  160. // ------------------------------------------------------------------------
  161. // --- FUNCTIONS PROTOTYPES
  162. // ------------------------------------------------------------------------
  163. void  ComputerMoves( void );
  164. void  HelpHuman( void );
  165. heuristic  MINiMAX( SpotStates    ThePlayer,
  166.             Go             &TheMove,
  167.             Board      TheBoard     );
  168.  
  169.  
  170. // -----------------------------------------------------------------------
  171. // --- FUNCTIONS
  172. // -----------------------------------------------------------------------
  173.  
  174. // -- Heap allocate fof the overloaded new -------------------------------
  175. void *getnew( void ) {
  176.       return ( MMHeap.Allocate() );
  177. };
  178.  
  179. // -- Computer moves -----------------------------------------------------
  180. void  ComputerMoves( void ) {
  181.  
  182.    Go        AGo;
  183.  
  184.    heuristic    H;
  185.  
  186.    char Buffer[40];
  187.  
  188.    // Say I'm thinking
  189.    GCI.Me.ShowPicture( PIC_THINKING );
  190.    GCI.Me.SayText( "OK.  GIVE ME A 'SEC.", NULL, NULL );
  191.    delay( 200 );
  192.  
  193.    // Amove exists.  Generate the move we want
  194.    MasterBoard.BrainIs( BrainSetting );
  195.    H = MINiMAX(   SPOT_BLACK,  AGo, MasterBoard    );
  196.  
  197.    // OK.  Show where I wanna go
  198.    GCI.Me.ShowPicture( PIC_LOOKRIGHT );
  199.    GCI.Me.SayText( "I WILL GO HERE", NULL, NULL );
  200.    GCI.Here( AGo );
  201.    delay( 1000 );
  202.  
  203.    // We have a move.  Apply it and show it.
  204.    MasterBoard.DoGo( AGo, SPOT_BLACK );
  205.    GCI.ShowBoard( MasterBoard );
  206.  
  207.  
  208.    // ---  OK.  Respond to the move.
  209.  
  210.    // If on, show H
  211.    if ( ShowH ) {
  212.       itoa( H, Buffer, 10);
  213.       XSet_Box( 112, 235, 80, 5, 0 );
  214.       XString4_C( 116, 235, 15, Buffer );
  215.    };
  216.  
  217.    // Show my reaction
  218.    if ( H > A_EXCELLENT ) {
  219.       GCI.Me.ShowPicture( PIC_HALFSMILE );
  220.       GCI.Me.SayText( "HE HE HE HE", "NOT LOOKING TO BAD", "FOR ME HERE" );
  221.    } else
  222.    if ( H > A_GOOD ) {
  223.       GCI.Me.ShowPicture( PIC_HALFSMILE );
  224.       GCI.Me.SayText( "WELL, NOT BAD.", NULL, NULL );
  225.    } else
  226.    if ( H > A_OK ) {
  227.       GCI.Me.ShowPicture( PIC_LOOKRIGHT );
  228.       GCI.Me.SayText( "HMMMMM...", "I'M NOT SURE WHAT TO", "THINK HERE." );
  229.    } else
  230.    if ( H > A_UNKNOWN ) {
  231.       GCI.Me.ShowPicture( PIC_CALM );
  232.       GCI.Me.SayText( "WELL.  THIS COULD GO", "EITHER WAY.", NULL );
  233.    } else
  234.    if ( H > A_UNGOOD ) {
  235.       GCI.Me.ShowPicture( PIC_CURIOUSFROWN );
  236.       GCI.Me.SayText( "UGG.", "THIS DOESN'T LOOK", "PROMISING" );
  237.    } else
  238.    if ( H > A_BAD ) {
  239.       GCI.Me.ShowPicture( PIC_LOOKRIGHTC );
  240.       GCI.Me.SayText( "OH.", "THIS IS NOT GOOD!", NULL );
  241.    } else {
  242.       GCI.Me.ShowPicture( PIC_FROWN );
  243.       GCI.Me.SayText( "I'M DEAD.", NULL, NULL );
  244.    };
  245.  
  246. };
  247.  
  248. // -- Help human with a move -----------------------------------------------
  249. void  HelpHuman( void ) {
  250.  
  251.    Go        AGo;
  252.  
  253.    char Buffer[40];
  254.  
  255.    // Say I'm thinking
  256.    GCI.Me.ShowPicture( PIC_THINKING );
  257.    GCI.Me.SayText( "OK.  GIVE ME A 'SEC.", NULL, NULL );
  258.    delay( 200 );
  259.  
  260.    // Amove exists.  Generate the move we want
  261.    MasterBoard.BrainIs( BrainSetting );
  262.    MINiMAX(   SPOT_WHITE,  AGo, MasterBoard    );
  263.  
  264.    // OK.  Show where I wanna go
  265.    GCI.Me.ShowPicture( PIC_IDEA );
  266.    GCI.Me.SayText( "I HAVE AN IDEA", NULL, NULL );
  267.    delay( 1000 );
  268.  
  269.    // OK.  Show where I wanna go
  270.    GCI.Me.ShowPicture( PIC_LOOKRIGHT );
  271.    GCI.Me.SayText( "I WOULD GO HERE", NULL, NULL );
  272.    GCI.Here( AGo );
  273.    delay( 1000 );
  274.  
  275.  
  276.  
  277. };
  278.  
  279.  
  280. // -- Handle the end of a game ---------------------------------------------
  281. void  EndGame( void ) {
  282.  
  283.    int     PlayerCount;
  284.  
  285.    // Count the players points and determine a win or loss
  286.    PlayerCount = MasterBoard.Count( SPOT_WHITE );
  287.  
  288.    if ( PlayerCount == 0 ) {
  289.  
  290.       // A draw
  291.       GCI.Me.ShowPicture( PIC_CALM );
  292.       GCI.Me.SayText( "HEY, HOW DID THAT", "HAPPENED.", "WE TIED!" );
  293.  
  294.    } else if ( PlayerCount < 0 ) {
  295.  
  296.       // A loss
  297.       GCI.Me.ShowPicture( PIC_VICTORY );
  298.       GCI.Me.SayText( "HA HA HA HA HA", "I WIN!", NULL );
  299.  
  300.  
  301.    } else {
  302.  
  303.       // A win
  304.       GCI.Me.ShowPicture( PIC_WHATUPSET );
  305.       GCI.Me.SayText( "HEY!!!", "HOW DID YOU DO THAT.", "YOU WIN" );
  306.  
  307.    }
  308.  
  309.    RunningScore += PlayerCount;
  310.    GCI.Score( RunningScore );
  311.  
  312. };
  313.  
  314. // -- Minimax function ------------------------------------------------------
  315. heuristic  MINiMAX( SpotStates    ThePlayer,
  316.             Go             &TheMove,
  317.             Board      TheBoard     ) {
  318.  
  319.    int      X, Y;
  320.  
  321.    heuristic    H;
  322.  
  323.    register int  Step;
  324.  
  325.    heuristic    PassThresh = VERY_BAD_THING;
  326.    heuristic    UseThresh  = VERY_GOOD_THING;
  327.  
  328.    Go        ChildGoTo[MAX_CHILDREN];
  329.    heuristic    ChildValue[MAX_CHILDREN];
  330.    MMNode    *Children[MAX_CHILDREN];
  331.    unsigned int NumberChildren;
  332.  
  333.  
  334.    // OK, do the drudgery.  Make the children..  For this player
  335.    // Only here will we have to remeber the moves.
  336.    NumberChildren = 0;
  337.    for ( X = 0; X < BOARDXSIZE; X++ ) {
  338.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  339.  
  340.      ChildGoTo[NumberChildren].XIs( X );
  341.      ChildGoTo[NumberChildren].YIs( Y );
  342.  
  343.      if ( TheBoard.ValidGo( ChildGoTo[NumberChildren], ThePlayer ) ) {
  344.  
  345.         // ---- Found a child.  Build 'em ----
  346.  
  347.         // Reset the Heap
  348.         MMHeap.Reset();
  349.  
  350.         Children[NumberChildren] =
  351.            new MMNode( TheBoard.Spots, ChildGoTo[NumberChildren],
  352.                ThePlayer                     );
  353.  
  354.         // If it is a NULL pointer, we are not getting anymore
  355.         if ( Children[NumberChildren] == NULL ) {
  356.            X = BOARDXSIZE;  // So it breaks out of both 'for's
  357.            break;
  358.         }
  359.  
  360.         Children[NumberChildren]->SetPly( 1 );
  361.  
  362.         // Oh No!  recursion!
  363.         ChildValue[NumberChildren] =
  364.            Children[NumberChildren]->TREE( -PassThresh, -UseThresh );
  365.                            // WARNING!!!  ^^^^^^^
  366.         // Do A/B pruning
  367.         H = ChildValue[NumberChildren];    // Negate it
  368.  
  369.         H = -H;
  370.         if ( H > PassThresh ) {
  371.  
  372.            // A better value for the pass threshhold
  373.            PassThresh = H;
  374.  
  375.         }
  376.  
  377.         // Prepare for another iteration.
  378.         NumberChildren++;
  379.         if ( NumberChildren == MAX_CHILDREN ) {
  380.            X = BOARDXSIZE;
  381.            break;
  382.         }
  383.  
  384.      }
  385.       }
  386.    }
  387.  
  388.    // Find the best move and value..  and return it
  389.    H = ChildValue[0];
  390.    X = 0;
  391.    for ( Step = 1; Step < NumberChildren; Step++ ) {
  392.       if ( ChildValue[Step] > H ) {
  393.      H = ChildValue[Step];
  394.      X = Step;
  395.       }
  396.    };
  397.    TheMove = ChildGoTo[X];
  398.  
  399.    return( H );
  400.  
  401.  
  402. };
  403.  
  404.  
  405.  
  406.  
  407. // ------------------------------------------------------------------------
  408. // --- MEMBERS
  409. // ------------------------------------------------------------------------
  410.  
  411. // --- MMNode class ---------------------------------------------------------
  412.  
  413. // -- The recursive tree function
  414. heuristic  MMNode::TREE( heuristic     UseThresh,  // For A/B pruning
  415.              heuristic     PassThresh,
  416.              BOOLEAN       Pass         // So we can tell an end move
  417.           ) {
  418.  
  419.    int      X, Y;
  420.    SpotStates   OtherGuy;
  421.    heuristic    H;
  422.  
  423.    register int  Step;
  424.  
  425.    // Who's the other guy?  (Just flip the owner)
  426.    if( Owner == SPOT_BLACK )
  427.       OtherGuy = SPOT_WHITE;
  428.    else
  429.       OtherGuy = SPOT_BLACK;
  430.  
  431.    // OK, have I reached the end of my plys for the level?
  432.    if ( CurrentPly == MaxPlys4Level[BrainLevel] ) {
  433.  
  434.       // Is is a win or loss situation.
  435.       if (Pass) {
  436.  
  437.      // If no more children can be created, then it is
  438.      for ( X = 0; X < BOARDXSIZE; X++ ) {
  439.         for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  440.  
  441.            AGoTo.XIs( X );
  442.            AGoTo.YIs( Y );
  443.  
  444.            if ( ValidGo( AGoTo, OtherGuy ) )
  445.           return ( Evaluate(Owner) );
  446.         }
  447.      }
  448.  
  449.      // No valid moves.  It is the end of a game.
  450.      return( WinOrLose(Owner) );
  451.  
  452.       } // end if pass situation
  453.  
  454.       // Just evaluate self and unroll recusive call
  455.       return( Evaluate(Owner) );
  456.  
  457.    };
  458.  
  459.    // OK, do the drudgery.  Make the children
  460.    NumberChildren = 0;
  461.    for ( X = 0; X < BOARDXSIZE; X++ ) {
  462.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  463.  
  464.      AGoTo.XIs( X );
  465.      AGoTo.YIs( Y );
  466.  
  467.      if ( ValidGo( AGoTo, OtherGuy ) ) {
  468.  
  469.         // Found a child.  Build 'em
  470.         Children[NumberChildren] = new MMNode( Spots, AGoTo, OtherGuy );
  471.  
  472.         // If it is a NULL pointer, we are not getting anymore
  473.         if ( Children[NumberChildren] == NULL ) {
  474.            X = BOARDXSIZE;
  475.            break;
  476.         }
  477.  
  478.         // Otherwise, tick up one more ply
  479.         CurrentPly++;
  480.  
  481.         // Oh No!  recursion!
  482.         H = Children[NumberChildren]->TREE( -PassThresh, -UseThresh );
  483.  
  484.         // Tack back the ply one
  485.         CurrentPly--;
  486.  
  487.         // Do A/B pruning
  488.         H = -H;    // Negate it
  489.         if ( H > PassThresh ) {
  490.  
  491.            // A better value for the pass threshhold
  492.            PassThresh = H;
  493.  
  494.         } else
  495.         if ( PassThresh >= UseThresh ) {
  496.  
  497.            // not a better value.  Stop pursuing this branch
  498.            return( PassThresh );
  499.  
  500.         };
  501.  
  502.         // Prepare for another iteration.
  503.         NumberChildren++;
  504.         if ( NumberChildren == MAX_CHILDREN ) {
  505.            X = BOARDXSIZE;
  506.            break;
  507.         }
  508.  
  509.      }
  510.       }
  511.    }
  512.  
  513.    // Ok, if no children, it is a pass.  If this function was called with
  514.    // a pass, then it is a game ender.  Evaluate as a winner or loser.
  515.    // Else, make a single pass child, and recurse into it
  516.    if ( NumberChildren == 0 ) {
  517.  
  518.       // Account for no children due to lack of memory
  519.       if ( Children[NumberChildren] == NULL ) return( Evaluate(Owner) );
  520.  
  521.       if ( Pass ) {
  522.  
  523.      return( WinOrLose(Owner) );
  524.  
  525.       } else {
  526.  
  527.      // Build the child if we can.  Else return current board eval
  528.      Children[NumberChildren] = new MMNode( Spots, OtherGuy );
  529.  
  530.      // Otherwise, tick up one more ply
  531.      CurrentPly++;
  532.  
  533.      // Oh No!  recursion!
  534.      PassThresh =
  535.         Children[NumberChildren]->TREE( -PassThresh, -UseThresh, TRUE );
  536.  
  537.      // Tack back the ply one
  538.      CurrentPly--;
  539.  
  540.      NumberChildren = 1;
  541.  
  542.       } // end if pass
  543.  
  544.    }
  545.  
  546.    // This joker has explored all it's children.
  547.    return( PassThresh );
  548.  
  549. };
  550.  
  551. // ------------------------------------------------------------------------
  552. // --- PRIMARY GAME ROUND ROUTINE - StartGame
  553. // ------------------------------------------------------------------------
  554.  
  555. STATUS  StartGame( SpotStates  WhoStarts ) {
  556.  
  557.    STATUS    TheStatus = STATUS_CONT;
  558.    SpotStates   WhosTurn  = WhoStarts;
  559.    USER_ACTION  Command;
  560.  
  561.    BOOLEAN    Pass = FALSE;
  562.    Go        AGo;
  563.  
  564.    // Reset the master board and show it
  565.    MasterBoard.InitBoard2Start();
  566.    GCI.ShowBoard( MasterBoard );
  567.  
  568.    // Keep playing
  569.    while( TheStatus == STATUS_CONT ) {
  570.  
  571.       if ( WhosTurn == SPOT_BLACK ) {
  572.  
  573.      // Computer turn
  574.  
  575.      // Is there a move?
  576.      if ( !MasterBoard.MoveExists( WhosTurn ) ) {
  577.  
  578.         // No move exists.  If end game, end.  Else pass.
  579.         if ( Pass ) {
  580.  
  581.            // End game
  582.            TheStatus = STATUS_END;
  583.            EndGame();
  584.  
  585.         } else {
  586.  
  587.            // Pass
  588.            GCI.Me.ShowPicture( PIC_CURIOUSFROWN );
  589.            GCI.Me.SayText( "HMMM!!!", "LOOKS LIKE I HAVE TO", "PASS" );
  590.            delay( 1000 );
  591.            Pass = TRUE;
  592.  
  593.         } // end if game end
  594.  
  595.      } else {
  596.  
  597.         // Clear the pass flag and move
  598.         Pass = FALSE;
  599.         ComputerMoves();
  600.  
  601.      }
  602.  
  603.       } else {
  604.  
  605.      // Player turn
  606.  
  607.      // Is there a move?
  608.      if ( !MasterBoard.MoveExists( WhosTurn ) ) {
  609.  
  610.         // No move exists.  If end game, end.  Else pass.
  611.         if ( Pass ) {
  612.  
  613.            // End game
  614.            TheStatus = STATUS_END;
  615.            EndGame();
  616.  
  617.         } else {
  618.  
  619.            // Pass
  620.            GCI.YouMustPass();
  621.            Pass = TRUE;
  622.  
  623.         } // end if game end
  624.  
  625.      } else {
  626.  
  627.         // Show valid moves
  628.         GCI.ShowValidMoves( MasterBoard );
  629.  
  630.         // Clear the pass flag
  631.         Pass = FALSE;
  632.  
  633.         // Loop until the player does something that shifts turns or quits
  634.         do {
  635.  
  636.            Command = GCI.WaitUser( AGo );
  637.  
  638.            // Switch through actions
  639.            switch( Command ) {
  640.  
  641.           // Set brain levels
  642.           case  CLICK_BRAIN1:
  643.                       BrainSetting = SIMPLETON;
  644.                       GCI.BrainSetting( SIMPLETON );
  645.                       break;
  646.           case  CLICK_BRAIN2:
  647.                       BrainSetting = DULLARD;
  648.                       GCI.BrainSetting( DULLARD );
  649.                       break;
  650.           case  CLICK_BRAIN3:
  651.                       BrainSetting = AVERAGE;
  652.                       GCI.BrainSetting( AVERAGE );
  653.                       break;
  654.           case  CLICK_BRAIN4:
  655.                       BrainSetting = SWIFT;
  656.                       GCI.BrainSetting( SWIFT );
  657.                       break;
  658.           case  CLICK_BRAIN5:
  659.                       BrainSetting = GENIUS;
  660.                       GCI.BrainSetting( GENIUS );
  661.                       break;
  662.           case  CLICK_BRAIN6:
  663.                       BrainSetting = EXPERIMENTAL;
  664.                       GCI.BrainSetting( EXPERIMENTAL );
  665.                       break;
  666.  
  667.           case  CLICK_HELP:   GCI.PushMainButton( HELP_BUTTON );
  668.                       HelpHuman();
  669.                       GCI.PopMainButton( HELP_BUTTON );
  670.                       break;
  671.  
  672.           case  CLICK_DONE:   GCI.PushMainButton( DONE_BUTTON );
  673.                       GCI.Me.ShowPicture( PIC_ARMSCROSS );
  674.                       GCI.Me.SayText( "CHICKEN!", "ARE YA?", NULL );
  675.                       delay( 1000 );
  676.                       GCI.PopMainButton( DONE_BUTTON );
  677.  
  678.                       // End it all
  679.                       if (GCI.YouSure()) {
  680.  
  681.                      TheStatus = STATUS_DONE;
  682.                      Command   = CLICK_DONE;
  683.  
  684.                       }  else {
  685.  
  686.                      GCI.Me.ShowPicture( PIC_CALM);
  687.                      GCI.Me.SayText( "GOOD", "THAT'S BETTER", NULL );
  688.                      delay( 1000 );
  689.  
  690.                      // Dummy command so it will
  691.                      // continue allowing user to click
  692.                      Command = CLICK_HELP;
  693.  
  694.                       }
  695.                       break;
  696.  
  697.           case  CLICK_NEW :   GCI.PushMainButton( NEW_BUTTON );
  698.                       GCI.Me.ShowPicture( PIC_WHAT );
  699.                       GCI.Me.SayText( "NEW GAME?", "I'M GONNA HAVE TO", "DOCK YOU 100 POINTS" );
  700.                       delay( 1000 );
  701.                       GCI.PopMainButton( NEW_BUTTON );
  702.  
  703.                       // End it all
  704.                       if (GCI.YouSure()) {
  705.  
  706.                      GCI.Me.ShowPicture( PIC_CALM);
  707.                      GCI.Me.SayText( "OK", "YOU'RE THE BOSS", NULL );
  708.  
  709.                      RunningScore -= 100;
  710.                      GCI.Score( RunningScore );
  711.  
  712.                      TheStatus = STATUS_NEW;
  713.                      Command   = CLICK_DONE;
  714.  
  715.                       }  else {
  716.  
  717.                      GCI.Me.ShowPicture( PIC_CALM);
  718.                      GCI.Me.SayText( "GOOD", "THAT'S BETTER", NULL );
  719.                      delay( 1000 );
  720.  
  721.                       }
  722.                       break;
  723.  
  724.           case  CLICK_BOARD:
  725.                       if ( MasterBoard.ValidGo(AGo, SPOT_WHITE) ) {
  726.  
  727.                      // A valid player move
  728.                      MasterBoard.DoGo( AGo, SPOT_WHITE );
  729.                      GCI.ShowBoard( MasterBoard );
  730.  
  731.                      // Break out
  732.                      Command = CLICK_DONE;
  733.                       }
  734.                       break;
  735.  
  736.  
  737.            } //end case
  738.  
  739.  
  740.         } while( Command != CLICK_DONE );
  741.  
  742.      } // end if move exists
  743.  
  744.       } // end if player turn
  745.  
  746.       // Flip turn
  747.       if   ( WhosTurn == SPOT_WHITE ) WhosTurn = SPOT_BLACK;
  748.       else WhosTurn = SPOT_WHITE;
  749.  
  750.    } // end while play
  751.  
  752.    return( TheStatus );
  753.  
  754.  
  755. };
  756.  
  757.  
  758.  
  759. // ------------------------------------------------------------------------
  760. // --- MAIN
  761. // ------------------------------------------------------------------------
  762. void  main( int  argn,  char  *argc[] ) {
  763.  
  764.    //                   SORRY!! ^^^ will cause a warning
  765.  
  766.    USER_ACTION    Command;
  767.    BOOLEAN    YouFirst;
  768.  
  769.    Go        DummyGo;
  770.  
  771.    STATUS    ReturnStatus;
  772.  
  773.    randomize();
  774.  
  775.    // Should we show the heuristic?
  776.    if ( argn > 1 ) ShowH = TRUE;
  777.  
  778.    // First time in, so go ahead and init main screen
  779.    GCI.InitMainScreen();
  780.  
  781.    // Scrub it
  782.    ReturnStatus = STATUS_CONT;
  783.  
  784.    // Loop through user actions
  785.    do {
  786.  
  787.       // Check for a new game request during last game
  788.       if ( ReturnStatus == STATUS_NEW ) {
  789.      Command = CLICK_NEW;
  790.  
  791.       } else
  792.      Command = GCI.WaitUser( DummyGo );
  793.  
  794.  
  795.       // Switch through actions
  796.       switch( Command ) {
  797.  
  798.      // Set brain levels
  799.      case  CLICK_BRAIN1:
  800.                  BrainSetting = SIMPLETON;
  801.                  GCI.BrainSetting( SIMPLETON );
  802.                  break;
  803.      case  CLICK_BRAIN2:
  804.                  BrainSetting = DULLARD;
  805.                  GCI.BrainSetting( DULLARD );
  806.                  break;
  807.      case  CLICK_BRAIN3:
  808.                  BrainSetting = AVERAGE;
  809.                  GCI.BrainSetting( AVERAGE );
  810.                  break;
  811.      case  CLICK_BRAIN4:
  812.                  BrainSetting = SWIFT;
  813.                  GCI.BrainSetting( SWIFT );
  814.                  break;
  815.      case  CLICK_BRAIN5:
  816.                  BrainSetting = GENIUS;
  817.                  GCI.BrainSetting( GENIUS );
  818.                  break;
  819.      case  CLICK_BRAIN6:
  820.                  BrainSetting = EXPERIMENTAL;
  821.                  GCI.BrainSetting( EXPERIMENTAL );
  822.                  break;
  823.  
  824.      case  CLICK_HELP:   GCI.PushMainButton( HELP_BUTTON );
  825.                  delay( BUTTON_TIME );
  826.                  GCI.PopMainButton( HELP_BUTTON );
  827.                  break;
  828.  
  829.      case  CLICK_NEW:    GCI.PushMainButton( NEW_BUTTON );
  830.                  delay( BUTTON_TIME );
  831.  
  832.                  GCI.PopMainButton( NEW_BUTTON );
  833.                  YouFirst = GCI.WhoFirst();
  834.                  if( YouFirst )
  835.                 ReturnStatus = StartGame(SPOT_WHITE);
  836.                  else
  837.                 ReturnStatus = StartGame(SPOT_BLACK);
  838.  
  839.                  // Check for quit
  840.                  if ( ReturnStatus == STATUS_DONE )
  841.                 Command = CLICK_DONE;
  842.  
  843.                  break;
  844.  
  845.      case  CLICK_DONE:   GCI.PushMainButton( DONE_BUTTON );
  846.                  delay( BUTTON_TIME );
  847.                  GCI.PopMainButton( DONE_BUTTON );
  848.                  break;
  849.  
  850.  
  851.       } //end case
  852.  
  853.  
  854.    } while( Command != CLICK_DONE );
  855.  
  856.    // Done
  857.    GCI.Me.ShowPicture( PIC_BYE );
  858.    GCI.Me.SayText( "GOODBYE!", NULL, NULL );
  859.    delay( 3000 );
  860.  
  861. };
  862.  
  863.  
  864.